#include "stm32_flash.h"
#include <string.h>

#define debug_print(x, ...)

/**
 * @brief  erase flash page
 * @param  startPage: start page to be erased
 * @param  endPage: end page to be erased
 * @retval HAL status
 */
HAL_StatusTypeDef stm32_flash_erase_page(int startPage, int endPage)
{

	FLASH_EraseInitTypeDef erase;
	HAL_StatusTypeDef stu;
	uint32_t pageError;
	// uint32_t  writeAddr  ;
	// writeAddr =  CHIP_FLASH_BASE_ADDR + CHIP_FLASH_PAGE_SIZE * (startPage) ;

	//  输入参数校验
	if (endPage < startPage)
		return HAL_ERROR;

	endPage++;

	HAL_FLASH_Unlock(); //  解锁flash

	while (startPage < endPage)
	{

		erase.TypeErase = FLASH_TYPEERASE_PAGES;							 //  页擦除
		erase.NbPages = 1;													 //  擦除一页
		erase.PageAddress = CHIP_FLASH_BASE_ADDR + CHIP_FLASH_PAGE_SIZE * (startPage); //  开始地址

		stu = HAL_FLASHEx_Erase(&erase, &pageError);
		if (stu == HAL_OK) //  擦除一页
		{
			debug_print("[stm32Flash]%d page erase true\r\n",startPage);
			// stm32_Delay_MS(20);
		}
		else
		{
			debug_print("[stm32Flash]%d~%d page erase false\r\n", startPage, endPage - 1);
			return stu;
		}
		startPage++;
	}
	HAL_FLASH_Lock(); //  上锁  flash

	return stu;
}


/**
 * @brief  Erase the page first and write it later
 * @param  page: page to be written
 * @param  p_buffer: pointer to data buffer
 * @param  size: data size
 * @note   size must be less than CHIP_FLASH_PAGE_SIZE
 * @retval HAL status
 */
HAL_StatusTypeDef stm32_flash_rewrite_page(int page, uint8_t *p_buffer, int size)
{
	int i, len = size;
	uint8_t *p_bufferStartAddr = p_buffer;
	FLASH_EraseInitTypeDef erase;
	uint32_t pageError;
	uint32_t writeAddr;
	writeAddr = CHIP_FLASH_BASE_ADDR + CHIP_FLASH_PAGE_SIZE * page;

	//   强行限制写入长度不能操作一页
	if (size > CHIP_FLASH_PAGE_SIZE)
		size = CHIP_FLASH_PAGE_SIZE;
	size += 3; //  字节长度转为字长度，不满一个字以一个字计算
	size /= 4;

	erase.TypeErase = FLASH_TYPEERASE_PAGES;			 //  页擦出
	erase.NbPages = 1;									 //  擦出一页
	erase.PageAddress = writeAddr;						 //  开始地址
	CHIP_OS_DI_INTERRUPT();
	HAL_FLASH_Unlock(); //  解锁flash
	if (HAL_FLASHEx_Erase(&erase, &pageError) == HAL_OK) //  擦除一页
	{
		debug_print("[stm32Flash]%d page erase true\r\n");
	}
	else
	{
		debug_print("[stm32Flash]%d page erase false\r\n");
	}
	//  写入数据
	for (i = 0; i < size; i++)
	{
		HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, writeAddr, *(uint32_t *)p_buffer);
		writeAddr += 4;
		p_buffer += 4;
	}
	//  校验写入的数据
	writeAddr = CHIP_FLASH_BASE_ADDR + CHIP_FLASH_PAGE_SIZE * page;
	if (memcmp(p_bufferStartAddr, (const void *)writeAddr, len) == 0)
	{
		debug_print("[stm32Flash]%d page write true\r\n");
	}
	else
	{
		debug_print("[stm32Flash]%d page write false\r\n");
	}
	HAL_FLASH_Lock(); //  上锁  flash

	CHIP_OS_EN_INTERRUPT();
	return HAL_OK;
}

/**
 * @brief  write data to flash
 * @param  page: page to be written
 * @param  p_buffer: pointer to data buffer
 * @param  size: data size
 * @retval HAL status
 */
HAL_StatusTypeDef stm32_flash_write_page(int page, uint8_t *p_buffer, int size)
{
	int i, len = size;
	union
	{
		uint8_t ch[4];
		uint32_t num;
	} word;

	uint8_t *p_bufferStartAddr = p_buffer;
	HAL_StatusTypeDef stu;

	uint32_t writeAddr;
	writeAddr = CHIP_FLASH_BASE_ADDR + CHIP_FLASH_PAGE_SIZE * page;

	HAL_FLASH_Unlock(); //  解锁flash

	//   强行限制写入长度不能操作一页
	// if(size > CHIP_FLASH_PAGE_SIZE) size = CHIP_FLASH_PAGE_SIZE ;
	size += 3; //  字节长度转为字长度，不满一个字以一个字计算
	size /= 4;

	for (i = 0; i < size; i++)
	{
		memcpy(word.ch, p_buffer, 4);
		stu = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, writeAddr, word.num);
		writeAddr += 4;
		p_buffer += 4;
	}

	//  校验写入的数据
	writeAddr = CHIP_FLASH_BASE_ADDR + CHIP_FLASH_PAGE_SIZE * page;
	if (memcmp(p_bufferStartAddr, (const void *)writeAddr, len) == 0)
	{
		 debug_print("[stm32Flash]%d page write true\r\n",page-stm32_Flash_APP_Start_Page);
		//  stm32_Delay_MS(10);
	}
	else
	{
		debug_print("[stm32Flash]%d page write false\r\n", page);
	}

	HAL_FLASH_Lock(); //  上锁  flash

	return stu;
}

/**
 * @brief  read data from flash
 * @param  page: page to be read
 * @param  buffer: pointer to data buffer
 * @param  size: data size
 * @retval HAL status
 */
HAL_StatusTypeDef stm32_flash_read_page(int page, uint8_t *buffer, int size)
{
	uint32_t endAddr = CHIP_FLASH_BASE_ADDR + CHIP_FLASH_PAGE_SIZE * page + size;
	uint32_t startAddr = CHIP_FLASH_BASE_ADDR + CHIP_FLASH_PAGE_SIZE * page;
	;
	int i = 0;

	while ((startAddr < endAddr))
	{
		buffer[i++] = (*(uint8_t *)startAddr);
		startAddr++;
	}
	return HAL_OK;
}
